#pragma once
#include "elisa/elisa.h"
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <gaol/gaol>

#include "Modeler.h"

#ifdef ELISA_PERFORMER
#include "elisa_chrono.h"
#endif

using namespace std;
using namespace elisa;

/* Problem: enfant2

Birch, B: "Noncongruence Subgroups, Covers and Drawings",
In "The Grothendieck Theory of Dessins d'Enfants", editor: Schneps, L.,
London Mathematical Society Lecture Series 200,
Cambridge University Press, pages 25-46, 1994. 
*/
class Enfant2 : public Modeler
{
private:
	Model _model;

	RealVar x1;
	RealVar x2;
	RealVar x3;
	RealVar x4;
	RealVar x5;
	RealVar x6;
	RealVar x7;
	RealVar x8;
	RealVar x9;
	RealVar x10;
	RealConstraint c1;
	RealConstraint c2;
	RealConstraint c3;
	RealConstraint c4;
	RealConstraint c5;
	RealConstraint c6;
	RealConstraint c7;
	RealConstraint c8;
	RealConstraint c9;
	RealConstraint c10;
	RealConstraint c11;
	RealConstraint c12;

public:
	Enfant2()
		: x1(Interval(-10,10), "x1"),
		  x2(Interval(-10,10), "x2"),
		  x3(Interval(-10,10), "x3"),
		  x4(Interval(-10,10), "x4"),
		  x5(Interval(-10,10), "x5"),
		  x6(Interval(-10,10), "x6"),
		  x7(Interval(-10,10), "x7"),
		  x8(Interval(-10,10), "x8"),
		  x9(Interval(-10,10), "x9"),
		  x10(Interval(-10,10), "x10"),
		  c1(16*x1*x6 + 18*x2*x5 + 20*x3*x8 == 0),
		  c2(7*x1*x5 + 8*x2*x8 == 0),
		  c3(210*x10 - 210 == 0),
		  c4(78*x2*x10 + 84*x3*x7 + 90*x4*x9 - 170*x1 + 102*x5 + 480*x6 == 0),
		  c5(136*x4*x10 - 114*x3 + 152*x9 + 720*x7 == 0),
		  c6(105*x3*x10 + 112*x4*x7 - 144*x2 + 126*x6  + 595*x9 == 0),
		  c7(180*x7 -80*x4 + 855*x10 == 0),
		  c8(40*x1*x7 + 44*x2*x9 + 48*x3*x6 + 52*x4*x5 + 280*x8 == 0),
		  c9(27*x1*x9 + 30*x2*x6 + 33*x3*x5 + 36*x4*x8 == 0),
		  c10(55*x1*x10 + 60*x2*x7 + 65*x3*x9 + 70*x4*x6 + 80*x8 + 375*x5 == 0),
		  c11(x9 - (114/152)*x3 + (1026/152)*x7 + (1453.5/152) == 0),
		  c12(x9 - (114/152)*x3 + (456/152)*x4 - (3420/152) == 0),
		  _model()
	{
	}

	elisa::Model & model()
	{
		_model = c1 && c2 && c3 && c4 && c5 && c6 && c7 && c8 && c9 && c10 && c11 && c12;
		return _model;
	}

	void print()
	{
		cout << '\t' << x1.getName() << " = " << x1.domain() << endl;
		cout << '\t' << x2.getName() << " = " << x2.domain() << endl;
		cout << '\t' << x3.getName() << " = " << x3.domain() << endl;
		cout << '\t' << x4.getName() << " = " << x4.domain() << endl;
		cout << '\t' << x5.getName() << " = " << x5.domain() << endl;
		cout << '\t' << x6.getName() << " = " << x6.domain() << endl;
		cout << '\t' << x7.getName() << " = " << x7.domain() << endl;
		cout << '\t' << x8.getName() << " = " << x8.domain() << endl;
		cout << '\t' << x9.getName() << " = " << x9.domain() << endl;
		cout << '\t' << x10.getName() << " = " << x10.domain() << endl;
	}

	RealVar & varX()
	{
		return x1;
	}
	RealVar & varY()
	{
		return x2;
	}
};
